﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Xceed.Silverlight.Data.Stats;

namespace Xceed.Silverlight.Data
{
  internal static class EnumeratorExtensions
  {
    #region ISyncDataSourceEnumerator Extensions

    internal static bool Move(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount )
    {
      return enumerator.Move( false, expectedMoveCount );
    }

    internal static bool Move(
      this ISyncDataSourceEnumerator enumerator,
      bool approximateMove, 
      long expectedMoveCount )
    {
      Nullable<long> notUsedActualCount;
      ICollection<DataPath> notUsed;
      EstimateInt64 notUsedTotalCount;
      RelativeOffset notUsedEndPositionOffset;

      return enumerator.MoveAndFetch(
               approximateMove,
               expectedMoveCount,
               0,
               out notUsedActualCount,
               out notUsed,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    internal static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      out Nullable<long> actualMoveCount,
      out ICollection<DataPath> fetchedItems,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      return enumerator.MoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               out actualMoveCount,
               out fetchedItems,
               out endPositionOffset,
               out totalCount );
    }

    public static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<DataPath> fetchedItems )
    {
      return enumerator.MoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               out fetchedItems);
    }

    public static bool MoveAndFetch(
      this ISyncDataSourceEnumerator enumerator,
      bool approximateMove,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<DataPath> fetchedItems )
    {
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.MoveAndFetch(
               approximateMove,
               expectedMoveCount,
               expectedFetchCount,
               out notUsedActualMoveCount,
               out fetchedItems,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    #endregion ISyncDataSourceEnumerator Extensions

    #region IAsyncDataSourceEnumerator Enxtensions

    internal static IMoveAndFetchAsyncResult BeginMoveAndFetch(
      this IAsyncDataSourceEnumerator enumerator,
      long expectedMoveCount,
      int expectedFetchCount,
      AsyncCallback asyncCallback,
      object asyncState )
    {
      return enumerator.BeginMoveAndFetch(
               false,
               expectedMoveCount,
               expectedFetchCount,
               asyncCallback,
               asyncState );
    }

    internal static bool SyncMoveAndFetch( 
      this IAsyncDataSourceEnumerator enumerator,
      bool approximateMove,
      long expectedMoveCount, 
      int expectedFetchCount,
      out Nullable<long> actualMoveCount,
      out ICollection<DataPath> fetchedItems,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      IMoveAndFetchAsyncResult asyncResult = enumerator.BeginMoveAndFetch( 
                                               approximateMove,
                                               expectedMoveCount, 
                                               expectedFetchCount, 
                                               null, 
                                               null ).EnsureSyncness();
      MoveAndFetchResult<DataPath> result = enumerator.EndMoveAndFetch( asyncResult );

      fetchedItems = result.FetchedItems;
      actualMoveCount = result.ActualMoveCount;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }

    internal static GroupFetchResult SyncFetchGroup( 
      this IAsyncDataSourceEnumerator enumerator, DataPath groupPath, 
      GroupTarget groupTarget, int expectedFetchCount )
    {
      IAsyncResult asyncResult = enumerator.BeginFetchGroup( groupPath, groupTarget, expectedFetchCount, null, null ).EnsureSyncness();
      return enumerator.EndFetchGroup( asyncResult );
    }

    internal static void SyncReset( this IAsyncDataSourceEnumerator enumerator )
    {
      IAsyncResult asyncResult = enumerator.BeginReset( null, null ).EnsureSyncness();
      enumerator.EndReset( asyncResult );
    }

    #endregion IAsyncDataSourceEnumerator Enxtensions

    #region ISyncEnumerator Extensions

    public static bool MoveToHome<T>( this ISyncEnumerator<T> enumerator )
    {
      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                    SourcePosition.BeforeFirst,
                                                    1,
                                                    0 );

      SourcePosition notUsedEndPosition;
      ICollection<T> notUsedfetchedItems;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out notUsedfetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool MoveToEnd<T>( this ISyncEnumerator<T> enumerator )
    {
      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                    SourcePosition.AfterLast,
                                                    -1,
                                                    0 );

      SourcePosition notUsedEndPosition;
      ICollection<T> notUsedfetchedItems;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out notUsedfetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool JumpMoveAndFetch<T>(
      this ISyncEnumerator<T> enumerator,
      SourcePosition startPosition,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<T> fetchedItems )
    {
      if( startPosition == null )
        throw new ArgumentNullException( "startPosition" );

      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters(
                                                startPosition,
                                                expectedMoveCount,
                                                expectedFetchCount );

      SourcePosition notUsedEndPosition;
      Nullable<long> notUsedActualMoveCount;
      RelativeOffset notUsedEndPositionOffset;
      EstimateInt64 notUsedTotalCount;

      return enumerator.JumpMoveAndFetch(
               parameters,
               out notUsedActualMoveCount,
               out fetchedItems,
               out notUsedEndPosition,
               out notUsedEndPositionOffset,
               out notUsedTotalCount );
    }

    public static bool JumpMoveAndFetch<T>(
      this ISyncEnumerator<T> enumerator,
      T startItem,
      long expectedMoveCount,
      int expectedFetchCount,
      out ICollection<T> fetchedItems )
    {
      return enumerator.JumpMoveAndFetch( 
        new ItemPosition( startItem ), 
        expectedMoveCount, 
        expectedFetchCount, 
        out fetchedItems );
    }

    public static ICollection<T> FetchAll<T>( this ISyncEnumerator<T> enumerator, bool reverseOrder )
    {
      ICollection<T> result;
      SourcePosition startPosition;
      int moveValue;
      int fetchValue;

      if(reverseOrder)
      {
        startPosition = SourcePosition.AfterLast;
        moveValue = -1;
        fetchValue = int.MinValue;
      }
      else
      {
        startPosition = SourcePosition.BeforeFirst;
        moveValue = 1;
        fetchValue = int.MaxValue;
      }

      enumerator.JumpMoveAndFetch(startPosition, moveValue, fetchValue, out result);

      if(result == null)
      {
        result = new List<T>(0);
      }

      return result;
    }

    #endregion ISyncEnumerator Extensions

    #region IAsyncEnumerator and IAsyncEnumerator<T> Extensions

    internal static CountResult SyncCount<T>(this IAsyncEnumerator<T> enumerator, CountParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginCount( parameters, null, null ).EnsureSyncness();
      return enumerator.EndCount( asyncResult );
    }

    internal static GroupCountResult SyncGroupCount<T>( this IAsyncEnumerator<T> enumerator, CountParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginGroupCount( parameters, null, null ).EnsureSyncness();
      return enumerator.EndGroupCount( asyncResult );
    }

    internal static StatResults SyncGetStatValues<T>( this IAsyncEnumerator<T> enumerator, StatParameters parameters )
    {
      IAsyncResult asyncResult = enumerator.BeginGetStatValues( parameters, null, null ).EnsureSyncness();
      return enumerator.EndGetStatValues( asyncResult );
    }

    internal static bool SyncJumpMoveAndFetch<T>( 
      this IAsyncEnumerator<T> enumerator,
      JumpMoveAndFetchParameters parameters,
      out Nullable<long> actualMoveCount, 
      out ICollection<T> fetchedItems, 
      out SourcePosition endPosition,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      JumpMoveAndFetchAsyncResult asyncResult = enumerator.BeginJumpMoveAndFetch(
                                                  parameters, 
                                                  null, 
                                                  null ).EnsureSyncness();
      JumpMoveAndFetchResult<T> result = enumerator.EndJumpMoveAndFetch( asyncResult );

      fetchedItems = result.FetchedItems;
      actualMoveCount = result.ActualMoveCount;
      endPosition = result.EndPositionObject;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }

    internal static bool SyncJumpMoveAndFetch( 
      this IAsyncEnumerator enumerator,
      JumpMoveAndFetchParameters parameters,
      out Nullable<long> actualMoveCount, 
      out ICollection fetchedObjects, 
      out SourcePosition endPosition,
      out RelativeOffset endPositionOffset,
      out EstimateInt64 totalCount )
    {
      JumpMoveAndFetchAsyncResult asyncResult = enumerator.BeginJumpMoveAndFetch(
                                                  parameters, 
                                                  null, 
                                                  null ).EnsureSyncness();
      JumpMoveAndFetchResult result = enumerator.EndJumpMoveAndFetch( asyncResult );

      fetchedObjects = result.FetchedObjects;
      actualMoveCount = result.ActualMoveCount;
      endPosition = result.EndPositionObject;
      endPositionOffset = result.EndPositionOffset;
      totalCount = result.TotalCount;

      return result.Result;
    }


    #endregion IAsyncEnumerator and IAsyncEnumerator<T> Extensions

    #region JumpMoveAndFetchParameters Extensions

    public static int GetFetchUnit( this JumpMoveAndFetchParameters parameters )
    {
      return DataUtils.GetUnit( parameters.ExpectedFetchCount );
    }

    public static int GetMoveUnit( this JumpMoveAndFetchParameters parameters )
    {
      return DataUtils.GetUnit( parameters.ExpectedMoveCount );
    }

    #endregion
  }
}
